import NetAdapter from "../adpapter/NetAdapter";
import GlobalData from "../GlobalData";

const { ccclass, menu, property } = cc._decorator;

@ccclass
@menu("UI/hotupdate/HotupdateManager")
export default class HotupdateManager extends cc.Component {
    protected static prefabUrl = "hotupdate/hotupdate";
    protected static className = "HotupdateManager";

    @property({ type: cc.Asset })
    manifestUrl: cc.Asset = null;

    @property(cc.ProgressBar)
    progressBar: cc.ProgressBar = null;

    @property(cc.Label)
    progressBarLabel: cc.Label = null;

    @property(cc.Node)
    nodeFail: cc.Node = null;

    public static instance: HotupdateManager = null;

    private _storagePath: string;
    private versionCompareHandle: any;
    private _am: any;
    private _updating: boolean = false;
    public static callback: Function;

    private _downFailList: Map<string, number> = new Map();

    // onInit(params) {
    //     this.callback = params[0];
    // }

    protected onLoad(): void {
        HotupdateManager.instance = this;
        console.log("Hotupdate onLoad");

        if (!cc.sys.isNative) {
            this.node.active = false;
            return;
        }

        NetAdapter.getUpdateHot().then((res: any) => {
            console.log("HotupdateManager getUpdateHot", res);
            let info = res;
            console.log("HotupdateManager getUpdateHot info.is_update ", info.is_update);
            let versions_no_update: any = res.versions_no_update;
            console.log("HotupdateManager getUpdateHot versions_no_update", JSON.stringify(versions_no_update));
            // 禁止热更新的版本
            versions_no_update.forEach(itemInfo => {
                if(itemInfo == GlobalData.inst.version)
                {
                    info.is_update = false;
                }
            });
            if (info.is_update) {
                //检查热更新
                this.initUpdateManager();
                this.hotMgrCheckUpdate();
            } else {
                this.node.active = false;
                HotupdateManager.callback && HotupdateManager.callback();
            }
        }).catch(err=>{
            console.log("getUpdateHot err", JSON.stringify(err));
            HotupdateManager.callback && HotupdateManager.callback();
        })
    }

    onStart() {
        console.log("Hotupdate onStart");
    }

    initUpdateManager() {
        console.log("initUpdateManager")
        this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'project-remote-asset');
        console.log("this._storagePath", this._storagePath)
        let that = this;
        this.versionCompareHandle = function (versionA, versionB) {
            console.log("本地版本为" + versionA + ', 服务器版本为' + versionB);
            // that.version.string = `local version:${versionA} server version:${versionB}`;
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                else {
                    return a - b;
                }
            }
            if (vB.length > vA.length) {
                return -1;
            }
            else {
                return 0;
            }
        };

        this._am = new jsb.AssetsManager('', this._storagePath, this.versionCompareHandle);

        this._am.setVerifyCallback(function (path, asset) {
            var compressed = asset.compressed;

            var expectedMD5 = asset.md5;

            var relativePath = asset.path;

            var size = asset.size;
            if (compressed) {
                console.log("Verification passed : " + relativePath);
                return true;
            }
            else {
                console.log("Verification passed : " + relativePath + ' (' + expectedMD5 + ')');
                return true;
            }
        });
        // if (cc.sys.os === cc.sys.OS_ANDROID) {
            //下载最大并发任务数
            this._am.setMaxConcurrentTask(2);
        // }
    }

    hotMgrCheckUpdate() {
        console.log("检测热更新");
        if (this._updating) {
            console.log('Checking or updating ...');
            return;
        }
        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            // Resolve md5 url
            var url = this.manifestUrl.nativeUrl;
            // if (cc.loader.md5Pipe) {
            //     url = cc.loader.md5Pipe.transformURL(url);
            // }
            this._am.loadLocalManifest(url);
        }
        if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
            console.log('Failed to load local manifest ...');
            return;
        }
        this._am.setEventCallback(this.checkCb.bind(this))
        this._am.checkUpdate();
        this._updating = true;
    }

    checkCb(event) {
        console.log('checkCb Code: ' + event.getEventCode());
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                console.log('找不到本地MANIFEST文件');
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                console.log('检测热更新失败 无法下载MANIFEST');
                this.updateFail();
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE://已经是服务器版本
                console.log('********已经是最新版本********');
                this.node.active = false;
                HotupdateManager.callback && HotupdateManager.callback("ok");
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND://找到新版本
                console.log('找到新版本.');
                this.progressBar.node.active = true;
                this._updating = false;
                this.hotUpdate();
                break;
            default:
                return;
        }
        // this._am.setEventCallback(null)
        // console.log("移除检测回调");
    }

    hotUpdate() {
        if (this._am && !this._updating) {
            this._am.setEventCallback(this.updateCb.bind(this))
            if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
                this._am.loadLocalManifest(this.manifestUrl.nativeUrl);
            }
            this._am.update();
            this._updating = true;
        }
    }
    conver(limit) {
        var size = "";
        if (limit < 0.1 * 1024) { //如果小于0.1KB转化成B  
            size = limit.toFixed(2) + "B";
        } else if (limit < 0.1 * 1024 * 1024) {//如果小于0.1MB转化成KB  
            size = (limit / 1024).toFixed(2) + "KB";
        } else if (limit < 0.1 * 1024 * 1024 * 1024) { //如果小于0.1GB转化成MB  
            size = (limit / (1024 * 1024)).toFixed(2) + "MB";
        } else { //其他转化成GB  
            size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB";
        }

        var sizestr = size + "";
        var len = sizestr.indexOf("\.");
        var dec = sizestr.substr(len + 1, 2);
        if (dec == "00") {//当小数点后为00时 去掉小数部分  
            return sizestr.substring(0, len) + sizestr.substr(len + 3, 2);
        }
        return sizestr;
    }

    updateCb(event) {
        var needRestart = false;
        var failed = false;
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                console.log("No local manifest file found, hot update skipped.");
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION:
                console.log("UPDATE_PROGRESSION----FILE:", event.getDownloadedFiles() + ' / ' + event.getTotalFiles());
                console.log("UPDATE_PROGRESSION----BYTE:", event.getDownloadedBytes() + ' / ' + event.getTotalBytes());

                var percent = Math.min(Number(event.getDownloadedBytes()) / Number(event.getTotalBytes()), 1);
                if (!isNaN(percent)) {
                    this.progressBar.progress = percent;
                    this.progressBarLabel.string = (percent * 100).toFixed(2) + "%";
                }

                // var msg = event.getMessage();
                // if (msg) {
                //     console.log("UPDATE_PROGRESSION----getPercent:", event.getPercent()/100 + '% : ' + msg);
                //     console.log("UPDATE_PROGRESSION----getPercentByFile:", event.getPercentByFile()/100 + '% : ' + msg);
                // }

                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                console.log('Fail to download manifest file, hot update skipped.');
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                console.log('Already up to date with the latest remote version.');
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED:
                console.log('Update finished. ' + event.getMessage());
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED:
                console.log('Update failed. ' + event.getMessage());
                let failed = false;
                this._downFailList.forEach((count) => {
                    if (count > 3) {
                        failed = true;
                    }
                });
                if (failed) {
                    // 超过3次失败，显示下载失败
                    // this._showUpdateFalid();
                } else {
                    cc.log(`HotUpdate failed...Restart Update`);
                    this._am.downloadFailedAssets();  // 重新下载失败的文件
                }
                // this.panel.retryBtn.active = true;
                // this._updating = false;
                // this._canRetry = true;
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING:
                failed = true;
                console.log('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage());
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS:
                console.log('Update failed. ' + event.getMessage());
                break;
            default:
                break;
        }

        if (failed) {
            this._am.setEventCallback(null)
            this._updating = false;
            this.updateFail();
        }

        if (needRestart) {
            console.log("Restart");
            cc.sys.localStorage.setItem('hotRestart', "1");

            this._am.setEventCallback(null)
            var searchPaths = jsb.fileUtils.getSearchPaths();
            var newPaths = this._am.getLocalManifest().getSearchPaths();
            Array.prototype.unshift(searchPaths, newPaths);
            cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);
            if (cc.sys.os === cc.sys.OS_IOS) {
                // 适配 iOS，避免缓存问题
                jsb.fileUtils.purgeCachedEntries();
            }
            cc.audioEngine.stopAll();
            cc.game.restart();
        }
    }

    // retry() {
    //     if (!this._updating && this._canRetry) {
    //         this.panel.retryBtn.active = false;
    //         this._canRetry = false;

    //         this.panel.info.string = 'Retry failed Assets...';
    //         this._am.downloadFailedAssets();
    //     }
    // }

    updateFail() {
        console.log("----------updateFail");
        // this.nodeFail.active = true;
        // 更新失败跳过更新
        this.node.active = false;
        HotupdateManager.callback && HotupdateManager.callback("error");
    }

    retryClick() {
        console.log("retryClick");
        this._am.setEventCallback(null)
        var searchPaths = jsb.fileUtils.getSearchPaths();
        var newPaths = this._am.getLocalManifest().getSearchPaths();
        Array.prototype.unshift(searchPaths, newPaths);
        cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
        jsb.fileUtils.setSearchPaths(searchPaths);
        cc.audioEngine.stopAll();
        cc.game.restart();
    }
}